#include "can.h"
#include <QDebug>
#include <iostream>

Can::Can(QObject *parent) :
    QObject(parent)
{
    id_equipment = 0;
    id_device = 0;
    set_default_can_obj();
}

Can::Can(int equipment, int device, QObject *parent) :
    QObject(parent),
    id_equipment(equipment),id_device(device)
{
    set_default_can_obj();
}

bool Can::connect() const{
    return VCI_OpenDevice(static_cast<DWORD>(id_device));
}

void Can::set_ids(const int equipment, const int device){
    id_equipment = equipment;
    id_device = device;
}

bool Can::set_config(const QString& acc_code,const QString& acc_mask,const QString& filter,const QString& timing0,const QString& timing1,const QString& mode){
    DWORD acc_code_dw = qstr2dword_hex(acc_code);
    DWORD acc_mask_dw = qstr2dword_hex(acc_mask);
    UCHAR filter_uc = qstr2uchar_hex(filter);
    UCHAR timing0_uc = qstr2uchar_hex(timing0);
    UCHAR timing1_uc = qstr2uchar_hex(timing1);
    UCHAR mode_uc = qstr2uchar_hex(mode);

    init_config.AccCode = acc_code_dw;
    init_config.AccMask = acc_mask_dw;
    init_config.Filter = filter_uc;
    init_config.Timing0 = timing0_uc;
    init_config.Timing1 = timing1_uc;
    init_config.Mode = mode_uc;
    init_config.Reserved = 0;
    DWORD id_equipment_uc = static_cast<DWORD>(id_equipment);
    DWORD id_device_uc = static_cast<DWORD>(id_device);
    return VCI_InitCan(id_equipment_uc,id_device_uc,&init_config);
}

bool Can::send_data(const QString& id_lower_computer,const QString& data0,const QString& data1,const QString& data2,const QString& data3){
    can_obj_send.ID = qstr2dword_hex(id_lower_computer);
    can_obj_send.Data[0] = qstr2uchar_hex(data0);//default = 1
    can_obj_send.Data[1] = qstr2uchar_hex(data1);//gain,x = 0~3,2^x,
    can_obj_send.Data[2] = qstr2uchar_hex(data2);//inter. time,y=0~3, 2^y, DN=2^(x*y)
    can_obj_send.Data[3] = qstr2uchar_hex(data3);//default = 0
        qDebug()<<can_obj_send.ID<<can_obj_send.Data;
    return VCI_Transmit(static_cast<DWORD>(id_equipment), static_cast<DWORD>(id_device), &can_obj_send);
}

bool Can::send_data(const QString &id_lower_computer, const QStringList &datas){
    can_obj_send.ID = qstr2dword_hex(id_lower_computer);
    for(int i=0;i<8;++i)//VCI_CAN_OBJ define
        can_obj_send.Data[i] = qstr2uchar_hex(datas.at(i));
    return VCI_Transmit(static_cast<DWORD>(id_equipment), static_cast<DWORD>(id_device), &can_obj_send);
}

LONGLONG Can::recieve_data(const QString& len,const QString& wait_time, QList<VCI_CAN_OBJ>& outputs) const{
    DWORD len_dw = static_cast<DWORD>(len.toLongLong());

    VCI_CAN_OBJ *p_recieve{nullptr};
    p_recieve = static_cast<VCI_CAN_OBJ*>(malloc(len_dw*sizeof (VCI_CAN_OBJ)));
    DWORD frame_cnts = VCI_Receive(static_cast<DWORD>(id_equipment), static_cast<DWORD>(id_device),
                                   p_recieve, len_dw, wait_time.toInt());
    LONGLONG frame_cntsL = static_cast<LONGLONG>(frame_cnts);

    outputs.clear();
    for(int i=0;i<frame_cntsL;++i)
        outputs.append(p_recieve[i]);

    free(p_recieve);
    return frame_cntsL;
}

QList<VCI_CAN_OBJ> Can::recieve_data(const QString& len,const QString& wait_time) const{
    DWORD len_dw = static_cast<DWORD>(len.toLongLong());

    VCI_CAN_OBJ *p_recieve{nullptr};
    p_recieve = static_cast<VCI_CAN_OBJ*>(malloc(len_dw*sizeof (VCI_CAN_OBJ)));
    DWORD frame_cnts = VCI_Receive(static_cast<DWORD>(id_equipment), static_cast<DWORD>(id_device),
                                   p_recieve, len_dw, wait_time.toInt());
    qDebug()<<frame_cnts;
    LONGLONG frame_cntsL = static_cast<LONGLONG>(frame_cnts);

    QList<VCI_CAN_OBJ> outputs;
    for(int i=0;i<frame_cntsL;++i)
        outputs.append(p_recieve[i]);

    free(p_recieve);
    return outputs;
//    return frame_cntsL;
}

bool Can::close(){
    return VCI_CloseDevice(static_cast<DWORD>(id_device));
}

DWORD Can::get_residue_cnts(){
    return VCI_GetReceiveNum(static_cast<DWORD>(id_equipment), static_cast<DWORD>(id_device));
}

bool Can::clear_buffer(){
    return VCI_ClearBuffer(static_cast<DWORD>(id_equipment),static_cast<DWORD>(id_device));
}

void Can::set_send_obj(const UCHAR send_type, const UCHAR remote_flag, const UCHAR extern_flag, const UCHAR data_len){
    can_obj_send.SendType = send_type;
    can_obj_send.RemoteFlag = remote_flag;
    can_obj_send.ExternFlag = extern_flag;
    can_obj_send.DataLen = data_len;
}

DWORD Can::qstr2dword_hex(const QString& qstr)const{
    return static_cast<DWORD>(qstr.toLongLong(nullptr,16));
}

UCHAR Can::qstr2uchar_hex(const QString &qstr) const{
    return static_cast<UCHAR>(qstr.toInt(nullptr,16));
}

void Can::set_default_can_obj() {
    can_obj_send.SendType = send_type;
    can_obj_send.RemoteFlag = remote_flag;
    can_obj_send.ExternFlag = extern_flag;
    can_obj_send.DataLen = data_len;
}
